package org.viettan.android.main.managers;

import java.lang.ref.WeakReference;

import org.viettan.android.main.R;
import org.viettan.android.main.io.EntityRetrievalException;
import org.viettan.android.main.io.Logger;

import roboguice.util.Strings;
import android.app.ProgressDialog;
import android.content.Context;
import android.widget.Toast;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.internal.Preconditions;

/**
 * The {@code DialogManager} manages alert notifications to the UI.
 */
@Singleton
public class DialogManager {

    private final Provider<Context> contextProvider;
    private final Logger logger;

    @Inject
    public DialogManager(Logger logger, Provider<Context> contextProvider) {
	Preconditions.checkNotNull(logger);
	Preconditions.checkNotNull(contextProvider);
	this.logger = logger;
	this.contextProvider = contextProvider;
    }

    private volatile int outstandingRequests = 0;

    // Why WeakReference? See
    // http://stackoverflow.com/questions/1111980/how-to-handle-screen-orientation-change-when-progress-dialog-and-background-thre
    private volatile WeakReference<ProgressDialog> currentProgressDialog;

    /**
     * Shows an alert message to the UI.
     *
     * @param message
     */
    public void showLong(int resourceId) {
	if (!ensureContext()) {
	    return;
	}

	showLong(getText(resourceId));
    }

    /**
     * Shows an alert message to the UI.
     *
     * @param message
     */
    public void showLong(String text) {
	if (!ensureContext()) {
	    return;
	}

	if (!Strings.isEmpty(text)) {
	    Toast.makeText(contextProvider.get(), text, Toast.LENGTH_LONG).show();
	}
    }

    /**
     * Shows an alert message that data cannot be retrieved from the network.
     *
     * @param context
     */
    public void showEntityRetrievalError(EntityRetrievalException ignored) {
	if (!ensureContext()) {
	    return;
	}

	showLong(R.string.error_data_retrieval);
    }

    /**
     * Signals that some progress is starting. This will display the "Please wait" dialog if a
     * dialog is not already showing. This method is thread-safe.
     */
    public synchronized void startProgress() {
	if (!ensureContext()) {
	    return;
	}

	// don't display if we already have outstanding requests
	if (outstandingRequests++ != 0) {
	    return;
	}

	String pleaseWait = getText(R.string.app_please_wait);
	currentProgressDialog = new WeakReference<ProgressDialog>(ProgressDialog.show(
		contextProvider.get(), null, pleaseWait));
    }

    /**
     * Signals that some progress has finished. The last outstanding progress request will
     * automatically hide the "Please wait" dialog. This method is thread-safe.
     */
    public synchronized void endProgress() {
	if (!ensureContext()) {
	    return;
	}

	// hide the dialog if the this was the last request
	if (--outstandingRequests <= 0) {
	    if (currentProgressDialog != null) {
		ProgressDialog progressDialog = currentProgressDialog.get();
		if (progressDialog != null) {
		    try {
			progressDialog.dismiss();
		    } catch (IllegalArgumentException ex) {
			// this happens on screen orientation changes. It's a pretty bad to just
			// catch this IAE. We really should fix the problem at the root.
			logger.warn("Progress dialog not attached to window probably due to screen orientation change");
		    }
		}

		currentProgressDialog = null;
	    }

	    // just in case
	    outstandingRequests = 0;
	}
    }

    private String getText(int resourceId) {
	return contextProvider.get().getString(resourceId);
    }

    private boolean ensureContext() {
	Context context = contextProvider.get();
	if (context == null) {
	    logger.warn("Unable to get context");
	    return false;
	}

	return true;
    }
}